home *** CD-ROM | disk | FTP | other *** search
- Subject: v14i063: Jove, an emacs variant, version 4.9, Part07/21
- Newsgroups: comp.sources.unix
- Sender: sources
- Approved: rsalz@uunet.UU.NET
-
- Submitted-by: Jonathan Payne <jpayne@cs.rochester.edu>
- Posting-number: Volume 14, Issue 63
- Archive-name: jove4.9/part07
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of archive 7 (of 21)."
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f './c.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'./c.c'\"
- else
- echo shar: Extracting \"'./c.c'\" \(14160 characters\)
- sed "s/^X//" >'./c.c' <<'END_OF_FILE'
- X/***************************************************************************
- X * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne. JOVE *
- X * is provided to you without charge, and with no warranty. You may give *
- X * away copies of JOVE, including sources, provided that this notice is *
- X * included in all the files. *
- X ***************************************************************************/
- X
- X/* Contains commands for C mode. Paren matching routines are in here. */
- X
- X#include "jove.h"
- X#include "re.h"
- X#include "ctype.h"
- X
- X#ifdef MAC
- X# undef private
- X# define private
- X#endif
- X
- X#ifdef LINT_ARGS
- private int
- X backslashed(char *, int);
- private void
- X do_expr(int, int),
- X FindMatch(int),
- X parse_cmt_fmt(char *),
- X strip_c(char *, char *);
- X#else
- private int
- X backslashed();
- private void
- X do_expr(),
- X FindMatch(),
- X parse_cmt_fmt(),
- X strip_c();
- X#endif /* LINT_ARGS */
- X
- X#ifdef MAC
- X# undef private
- X# define private static
- X#endif
- X
- X
- private int
- backslashed(lp, cpos)
- register char *lp;
- register int cpos;
- X{
- X register int cnt = 0;
- X
- X while (cpos > 0 && lp[--cpos] == '\\')
- X cnt += 1;
- X return (cnt % 2);
- X}
- X
- private char *p_types = "(){}[]";
- private int mp_kind;
- X#define MP_OKAY 0
- X#define MP_MISMATCH 1
- X#define MP_UNBALANCED 2
- X
- void
- mp_error()
- X{
- X switch (mp_kind) {
- X case MP_MISMATCH:
- X message("[Mismatched parentheses]");
- X break;
- X
- X case MP_UNBALANCED:
- X message("[Unbalanced parenthesis]");
- X break;
- X
- X case MP_OKAY:
- X default:
- X return;
- X }
- X rbell();
- X}
- X
- X/* Search from the current position for the paren that matches p_type.
- X Search in the direction dir. If can_mismatch is YES then it is okay
- X to have mismatched parens. If stop_early is YES then when an open
- X paren is found at the beginning of a line, it is assumed that there
- X is no point in backing up further. This is so when you hit tab or
- X LineFeed outside, in-between procedure/function definitions, it won't
- X sit there searching all the way to the beginning of the file for a
- X match that doesn't exist. {forward,backward}-s-expression are the
- X only ones that insist on getting the "true" story. */
- X
- Bufpos *
- m_paren(p_type, dir, can_mismatch, can_stop)
- char p_type;
- register int dir;
- X{
- X static Bufpos ret;
- X Bufpos savedot,
- X *sp;
- X char re_buf[100],
- X *re_alts[NALTS];
- X int count = 0;
- X register char *lp,
- X c;
- X char p_match,
- X re_str[128],
- X *cp,
- X quote_c = 0;
- X register int c_char;
- X int in_comment = -1,
- X stopped = NO;
- X
- X sprintf(re_str, "[(){}[\\]%s]", (MajorMode(CMODE)) ? "/\"'" : "\"");
- X REcompile(re_str, 1, re_buf, re_alts);
- X if (cp = index(p_types, p_type))
- X p_match = cp[dir];
- X else
- X complain("[Cannot match %c's]", p_type);
- X DOTsave(&savedot);
- X
- X /* To make things a little faster I avoid copying lines into
- X linebuf by setting curline and curchar by hand. Warning:
- X this is slightly to very risky. When I did this there were
- X lots of problems with procedures that expect the contents of
- X curline to be in linebuf. */
- X while (count >= 0) {
- X sp = docompiled(dir, re_buf, re_alts);
- X if (sp == 0)
- X break;
- X lp = lbptr(sp->p_line);
- X
- X if (sp->p_line != curline)
- X /* let's assume that strings do NOT go over line
- X bounderies (for now don't check for wrapping
- X strings) */
- X quote_c = 0;
- X curline = sp->p_line;
- X curchar = sp->p_char; /* here's where I cheat */
- X c_char = curchar;
- X if (dir == FORWARD)
- X c_char -= 1;
- X if (backslashed(lp, c_char))
- X continue;
- X c = lp[c_char];
- X /* check if this is a comment (if we're not inside quotes) */
- X if (quote_c == 0 && c == '/') {
- X int new_ic;
- X
- X if ((c_char != 0) && lp[c_char - 1] == '*') {
- X new_ic = (dir == FORWARD) ? NO : YES;
- X if (new_ic == NO && in_comment == -1) {
- X count = 0;
- X quote_c = 0;
- X }
- X } else if (lp[c_char + 1] == '*') {
- X new_ic = (dir == FORWARD) ? YES : NO;
- X if (new_ic == NO && in_comment == -1) {
- X count = 0;
- X quote_c = 0;
- X }
- X }
- X in_comment = new_ic;
- X }
- X if (in_comment == YES)
- X continue;
- X if (c == '"' || c == '\'') {
- X if (quote_c == c)
- X quote_c = 0;
- X else if (quote_c == 0)
- X quote_c = c;
- X }
- X if (quote_c != 0)
- X continue;
- X if (isopenp(c)) {
- X count += dir;
- X if (c_char == 0 && can_stop == YES && count >= 0) {
- X stopped = YES;
- X break;
- X }
- X } else if (isclosep(c))
- X count -= dir;
- X }
- X
- X ret.p_line = curline;
- X ret.p_char = curchar;
- X
- X curline = savedot.p_line;
- X curchar = savedot.p_char; /* here's where I undo it */
- X
- X if (count >= 0)
- X mp_kind = MP_UNBALANCED;
- X else if (c != p_match)
- X mp_kind = MP_MISMATCH;
- X else
- X mp_kind = MP_OKAY;
- X
- X /* If we stopped (which means we were allowed to stop) and there
- X was an error, we clear the error so no error message is printed.
- X An error should be printed ONLY when we are sure about the fact,
- X namely we didn't stop prematurely HOPING that it was the right
- X answer. */
- X if (stopped && mp_kind != MP_OKAY) {
- X mp_kind = MP_OKAY;
- X return 0;
- X }
- X if (mp_kind == MP_OKAY || (mp_kind == MP_MISMATCH && can_mismatch == YES))
- X return &ret;
- X return 0;
- X}
- X
- private void
- do_expr(dir, skip_words)
- register int dir;
- X{
- X register char c,
- X syntax = (dir == FORWARD) ? _Op : _Cl;
- X
- X if (dir == BACKWARD)
- X b_char(1);
- X c = linebuf[curchar];
- X for (;;) {
- X if (!skip_words && ismword(c)) {
- X WITH_TABLE(curbuf->b_major)
- X if(dir == FORWARD) f_word(1);
- X else b_word(1);
- X END_TABLE();
- X break;
- X } else if (has_syntax(c, syntax)) {
- X FindMatch(dir);
- X break;
- X }
- X f_char(dir);
- X if (eobp() || bobp())
- X return;
- X c = linebuf[curchar];
- X }
- X}
- X
- void
- FSexpr()
- X{
- X register int num = arg_value();
- X
- X if (num < 0) {
- X set_arg_value(-num);
- X BSexpr();
- X }
- X while (--num >= 0)
- X do_expr(FORWARD, NO);
- X}
- X
- void
- FList()
- X{
- X register int num = arg_value();
- X
- X if (num < 0) {
- X set_arg_value(-num);
- X BList();
- X }
- X while (--num >= 0)
- X do_expr(FORWARD, YES);
- X}
- X
- void
- BSexpr()
- X{
- X register int num = arg_value();
- X
- X if (num < 0) {
- X negate_arg_value();
- X FSexpr();
- X }
- X while (--num >= 0)
- X do_expr(BACKWARD, NO);
- X}
- X
- void
- BList()
- X{
- X register int num = arg_value();
- X
- X if (num < 0) {
- X negate_arg_value();
- X FList();
- X }
- X while (--num >= 0)
- X do_expr(BACKWARD, YES);
- X}
- X
- void
- BUpList()
- X{
- X Bufpos *mp;
- X char c = (MajorMode(CMODE) ? '}' : ')');
- X
- X mp = m_paren(c, BACKWARD, NO, YES);
- X if (mp == 0)
- X mp_error();
- X else
- X SetDot(mp);
- X}
- X
- void
- FDownList()
- X{
- X Bufpos *sp;
- X char *sstr = (MajorMode(CMODE) ? "[{([\\])}]" : "[()]"),
- X *lp;
- X
- X sp = dosearch(sstr, FORWARD, YES);
- X if (sp != 0)
- X lp = lcontents(sp->p_line);
- X if (sp == 0 || has_syntax(lp[sp->p_char - 1], _Cl))
- X complain("[No contained expression]");
- X SetDot(sp);
- X}
- X
- X/* Move to the matching brace or paren depending on the current position
- X in the buffer. */
- X
- private void
- FindMatch(dir)
- X{
- X register Bufpos *bp;
- X register char c = linebuf[curchar];
- X
- X if ((index(p_types, c) == 0) ||
- X (backslashed(linebuf, curchar)))
- X complain((char *) 0);
- X if (dir == FORWARD)
- X f_char(1);
- X bp = m_paren(c, dir, YES, NO);
- X if (dir == FORWARD)
- X b_char(1);
- X if (bp != 0)
- X SetDot(bp);
- X mp_error(); /* if there is an error the user wants to
- X know about it */
- X}
- X
- Bufpos *
- c_indent(incrmt)
- X{
- X Bufpos *bp;
- X int indent = 0;
- X
- X if (bp = m_paren('}', BACKWARD, NO, YES)) {
- X Bufpos save;
- X
- X DOTsave(&save);
- X SetDot(bp);
- X ToIndent();
- X indent = calc_pos(linebuf, curchar);
- X SetDot(&save);
- X }
- X if (incrmt) {
- X if (indent == 0)
- X incrmt = tabstop;
- X else
- X incrmt = (tabstop - (indent%tabstop));
- X }
- X n_indent(indent + incrmt);
- X return bp;
- X}
- X
- X#ifdef CMT_FMT
- X
- char CmtFmt[80] = "/*%n%! * %c%!%n */";
- X
- void
- Comment()
- X{
- X FillComment(CmtFmt);
- X}
- X
- X/* Strip leading and trailing white space. Skip over any imbedded '\r's. */
- X
- private void
- strip_c(from, to)
- char *from,
- X *to;
- X{
- X register char *fr_p = from,
- X *to_p = to,
- X c;
- X
- X while (c = *fr_p) {
- X if (c == ' ' || c == '\t' || c == '\r')
- X fr_p += 1;
- X else
- X break;
- X }
- X while (c = *fr_p) {
- X if (c != '\r')
- X *to_p++ = c;
- X fr_p += 1;
- X }
- X while (--to_p >= to)
- X if (*to_p != ' ' && *to_p != '\t')
- X break;
- X *++to_p = '\0';
- X}
- X
- private char open_c[20], /* the open comment format string */
- X open_pat[20], /* the search pattern for open comment */
- X l_header[20], /* the prefix for each comment line */
- X l_trailer[20], /* the suffix ... */
- X close_c[20],
- X close_pat[20];
- X
- private char *comment_body[] = {
- X open_c,
- X l_header,
- X l_trailer,
- X close_c
- X};
- X
- private int nlflags;
- X
- X/* Fill in the data structures above from the format string. Don't return
- X if there's trouble. */
- X
- private void
- parse_cmt_fmt(str)
- char *str;
- X{
- X register char *fmtp = str;
- X register char **c_body = comment_body,
- X *body_p = *c_body;
- X int c,
- X newlines = 1;
- X
- X /* pick apart the comment string */
- X while (c = *fmtp++) {
- X if (c != '%') {
- X *body_p++ = c;
- X continue;
- X }
- X switch(c = *fmtp++) {
- X case 'n':
- X if (newlines == 2 || newlines == 3)
- X complain("%n not allowed in line header or trailer: %s",
- X fmtp - 2);
- X nlflags += newlines;
- X *body_p++ = '\r';
- X break;
- X case 't':
- X *body_p++ = '\t';
- X break;
- X case '%':
- X *body_p++ = '%';
- X break;
- X case '!':
- X case 'c':
- X newlines += 1;
- X *body_p++ = '\0';
- X body_p = *++c_body;
- X break;
- X default:
- X complain("[Unknown comment escape: %%%c]", c);
- X /* VARARGS */
- X break;
- X }
- X }
- X *body_p = '\0';
- X /* make search patterns */
- X strip_c(open_c, open_pat);
- X strip_c(close_c, close_pat);
- X}
- X
- X#define NL_IN_OPEN_C ((nlflags % 4) == 1)
- X#define NL_IN_CLOSE_C (nlflags >= 4)
- X
- void
- FillComment(format)
- char *format;
- X{
- X int saveRMargin,
- X indent_pos,
- X close_at_dot = NO,
- X slen,
- X header_len,
- X trailer_len;
- X register char *cp;
- X static char inside_err[] = "[Must be between %s and %s to re-format]";
- X Bufpos open_c_pt,
- X close_c_pt,
- X tmp_bp,
- X *match_o,
- X *match_c;
- X Mark *entry_mark,
- X *open_c_mark,
- X *savedot;
- X
- X parse_cmt_fmt(format);
- X /* figure out if we're "inside" a comment */
- X if ((match_o = dosearch(open_pat, BACKWARD, 0)) == 0)
- X /* VARARGS */
- X complain("No opening %s to match to.", open_pat);
- X open_c_pt = *match_o;
- X if ((match_c = dosearch(close_pat, BACKWARD, NO)) != 0 &&
- X inorder(open_c_pt.p_line, open_c_pt.p_char,
- X match_c->p_line, match_c->p_char))
- X complain(inside_err, open_pat, close_pat);
- X if ((match_o = dosearch(open_pat, FORWARD, NO)) != 0) {
- X tmp_bp = *match_o;
- X match_o = &tmp_bp;
- X }
- X if ((match_c = dosearch(close_pat, FORWARD, 0)) != (Bufpos *) 0)
- X close_c_pt = *match_c;
- X
- X /* Here's where we figure out whether to format from dot or from
- X the close comment. Note that we've already searched backwards to
- X find the open comment symbol for the comment we are formatting.
- X The open symbol mentioned below refers to the possible existence
- X of the next comment. There are 5 cases:
- X 1) no open or close symbol ==> dot
- X 2) open, but no close symbol ==> dot
- X 3) close, but no open ==> close
- X 4) open, close are inorder ==> dot
- X 5) open, close are not inorder ==> close */
- X
- X
- X if (match_o == (Bufpos *) 0) {
- X if (match_c == (Bufpos *) 0)
- X close_at_dot = YES;
- X } else if (match_c == (Bufpos *) 0)
- X close_at_dot = YES;
- X else if (inorder(match_o->p_line, match_o->p_char,
- X match_c->p_line, match_c->p_char))
- X close_at_dot = YES;
- X if (close_at_dot) {
- X close_c_pt.p_line = curline;
- X close_c_pt.p_char = curchar;
- X } else {
- X SetDot(match_c);
- X }
- X SetDot(&open_c_pt);
- X open_c_mark = MakeMark(curline, curchar, M_FLOATER);
- X indent_pos = calc_pos(linebuf, curchar);
- X /* search for a close comment; delete it if it exits */
- X SetDot(&close_c_pt);
- X if (close_at_dot == 0) {
- X slen = strlen(close_pat);
- X while (slen--)
- X del_char(BACKWARD, 1);
- X }
- X entry_mark = MakeMark(curline, curchar, M_FLOATER);
- X ToMark(open_c_mark);
- X /* always separate the comment body from anything preceeding it */
- X LineInsert(1);
- X DelWtSpace();
- X Bol();
- X for (cp = open_c; *cp; cp++) {
- X if (*cp == '\r') {
- X if (!eolp())
- X LineInsert(1);
- X else
- X line_move(FORWARD, 1, NO);
- X } else if (*cp == ' ' || *cp == '\t') {
- X if (linebuf[curchar] != *cp)
- X insert_c(*cp, 1);
- X } else
- X /* Since we matched the open comment string on this
- X line, we don't need to worry about crossing line
- X boundaries. */
- X curchar += 1;
- X }
- X savedot = MakeMark(curline, curchar, M_FLOATER);
- X
- X /* We need to strip the line header pattern of leading white space
- X since we need to match the line after all of its leading
- X whitespace is gone. */
- X for (cp = l_header; *cp && (isspace(*cp)); cp++)
- X ;
- X header_len = strlen(cp);
- X trailer_len = strlen(l_trailer);
- X
- X /* Strip each comment line of the open and close comment strings
- X before reformatting it. */
- X
- X do {
- X Bol();
- X DelWtSpace();
- X if (header_len && !strncmp(linebuf, cp, header_len))
- X del_char(FORWARD, header_len);
- X if (trailer_len) {
- X Eol();
- X if ((curchar > trailer_len) &&
- X (!strncmp(&linebuf[curchar - trailer_len],
- X l_trailer, trailer_len)))
- X del_char(BACKWARD, trailer_len);
- X }
- X if (curline->l_next != 0)
- X line_move(FORWARD, 1, NO);
- X else
- X break;
- X } while (curline != entry_mark->m_line->l_next);
- X
- X do_set_mark(savedot->m_line, savedot->m_char);
- X ToMark(entry_mark);
- X saveRMargin = RMargin;
- X RMargin = saveRMargin - strlen(l_header) -
- X strlen(l_trailer) - indent_pos + 2;
- X do_rfill(NO);
- X RMargin = saveRMargin;
- X /* get back to the start of the comment */
- X PopMark();
- X do {
- X if (curline == open_c_mark->m_line->l_next) {
- X ;
- X } else {
- X n_indent(indent_pos);
- X ins_str(l_header, NO);
- X }
- X Eol();
- X if (!NL_IN_CLOSE_C && (curline == entry_mark->m_line))
- X ;
- X else
- X ins_str(l_trailer, NO);
- X if (curline->l_next != 0)
- X line_move(FORWARD, 1, NO);
- X else
- X break;
- X } while (curline != entry_mark->m_line->l_next);
- X /* handle the close comment symbol */
- X if (curline == entry_mark->m_line->l_next) {
- X line_move(BACKWARD, 1, NO);
- X Eol();
- X }
- X DelWtSpace();
- X /* if the addition of the close symbol would cause the line to be
- X too long, put the close symbol on the next line. */
- X if (!(NL_IN_CLOSE_C) &&
- X strlen(close_c) + calc_pos(linebuf, curchar) > RMargin) {
- X LineInsert(1);
- X n_indent(indent_pos);
- X }
- X for (cp = close_c; *cp; cp++) {
- X if (*cp == '\r') {
- X LineInsert(1);
- X n_indent(indent_pos);
- X } else
- X insert_c(*cp, 1);
- X }
- X ToMark(open_c_mark);
- X Eol();
- X del_char(FORWARD, 1);
- X}
- X
- X#endif /* CMT_FMT */
- X
- END_OF_FILE
- if test 14160 -ne `wc -c <'./c.c'`; then
- echo shar: \"'./c.c'\" unpacked with wrong size!
- fi
- # end of './c.c'
- fi
- if test -f './insert.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'./insert.c'\"
- else
- echo shar: Extracting \"'./insert.c'\" \(14465 characters\)
- sed "s/^X//" >'./insert.c' <<'END_OF_FILE'
- X/***************************************************************************
- X * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne. JOVE *
- X * is provided to you without charge, and with no warranty. You may give *
- X * away copies of JOVE, including sources, provided that this notice is *
- X * included in all the files. *
- X ***************************************************************************/
- X
- X#include "jove.h"
- X#include "ctype.h"
- X#include "table.h"
- X
- X#ifdef MAC
- X# undef private
- X# define private
- X#endif
- X
- X#ifdef LINT_ARGS
- private int
- X newchunk(void);
- private void
- X init_specials(void),
- X remfreelines(struct chunk *);
- X#else
- private int
- X newchunk();
- private void
- X init_specials(),
- X remfreelines();
- X#endif /* LINT_ARGS */
- X
- X#ifdef MAC
- X# undef private
- X# define private static
- X#endif
- X
- X/* Make a newline after AFTER in buffer BUF, UNLESS after is 0,
- X in which case we insert the newline before after. */
- X
- Line *
- listput(buf, after)
- register Buffer *buf;
- register Line *after;
- X{
- X register Line *newline = nbufline();
- X
- X if (after == 0) { /* Before the first line */
- X newline->l_next = buf->b_first;
- X newline->l_prev = 0;
- X buf->b_first = newline;
- X } else {
- X newline->l_prev = after;
- X newline->l_next = after->l_next;
- X after->l_next = newline;
- X }
- X if (newline->l_next)
- X newline->l_next->l_prev = newline;
- X else
- X if (buf)
- X buf->b_last = newline;
- X if (buf && buf->b_dot == 0)
- X buf->b_dot = newline;
- X return newline;
- X}
- X
- X/* Divide the current line and move the current line to the next one */
- X
- void
- LineInsert(num)
- register int num;
- X{
- X char newline[LBSIZE];
- X register Line *newdot,
- X *olddot;
- X int oldchar;
- X
- X olddot = curline;
- X oldchar = curchar;
- X
- X newdot = curline;
- X while (--num >= 0) {
- X newdot = listput(curbuf, newdot);
- X SavLine(newdot, NullStr);
- X }
- X
- X modify();
- X if (curchar != 0) {
- X strcpy(newline, &linebuf[curchar]);
- X linebuf[curchar] = '\0'; /* Shorten this line */
- X SavLine(curline, linebuf);
- X strcpy(linebuf, newline);
- X } else { /* Redisplay optimization */
- X newdot->l_dline = curline->l_dline;
- X SavLine(curline, NullStr);
- X }
- X
- X makedirty(curline);
- X curline = newdot;
- X curchar = 0;
- X makedirty(curline);
- X IFixMarks(olddot, oldchar, curline, curchar);
- X}
- X
- X/* Makes the indent of the current line == goal. If the current indent
- X is greater than GOAL it deletes. If more indent is needed, it uses
- X tabs and spaces to get to where it's going. */
- X
- void
- n_indent(goal)
- register int goal;
- X{
- X int dotcol,
- X incrmt;
- X
- X ToIndent();
- X dotcol = calc_pos(linebuf, curchar);
- X if (goal < dotcol) {
- X DelWtSpace();
- X dotcol = 0;
- X }
- X
- X for (;;) {
- X incrmt = (tabstop - (dotcol % tabstop));
- X if (dotcol + incrmt > goal)
- X break;
- X insert_c('\t', 1);
- X dotcol += incrmt;
- X }
- X if (dotcol != goal)
- X insert_c(' ', (goal - dotcol));
- X}
- X
- X#ifdef ABBREV
- void
- MaybeAbbrevExpand()
- X{
- X if (MinorMode(Abbrev) && !ismword(LastKeyStruck) &&
- X !bolp() && ismword(linebuf[curchar - 1]))
- X AbbrevExpand();
- X}
- X#endif
- X
- void
- SelfInsert()
- X{
- X#ifdef ABBREV
- X MaybeAbbrevExpand();
- X#endif
- X if (LastKeyStruck != CTL('J') && MinorMode(OverWrite)) {
- X register int num,
- X i;
- X
- X for (i = 0, num = arg_value(); i < num; i++) {
- X int pos = calc_pos(linebuf, curchar);
- X
- X if (!eolp()) {
- X if (linebuf[curchar] == '\t') {
- X if ((pos + 1) == ((pos + tabstop) - (pos % tabstop)))
- X del_char(FORWARD, 1);
- X } else
- X del_char(FORWARD, 1);
- X }
- X insert_c(LastKeyStruck, 1);
- X }
- X } else
- X Insert(LastKeyStruck);
- X
- X if (MinorMode(Fill) && (curchar >= RMargin ||
- X (calc_pos(linebuf, curchar) >= RMargin))) {
- X int margin;
- X Bufpos save;
- X
- X if (MinorMode(Indent)) {
- X DOTsave(&save);
- X ToIndent();
- X margin = calc_pos(linebuf, curchar);
- X SetDot(&save);
- X } else
- X margin = LMargin;
- X DoJustify(curline, 0, curline,
- X curchar + strlen(&linebuf[curchar]), 1, margin);
- X }
- X}
- X
- void
- Insert(c)
- X{
- X if (c == CTL('J'))
- X LineInsert(arg_value());
- X else
- X insert_c(c, arg_value());
- X}
- X
- X/* insert character C N times at point */
- void
- insert_c(c, n)
- X{
- X if (n <= 0)
- X return;
- X modify();
- X makedirty(curline);
- X ins_c(c, linebuf, curchar, n, LBSIZE);
- X IFixMarks(curline, curchar, curline, curchar + n);
- X curchar += n;
- X}
- X
- X/* Tab in to the right place for C mode */
- X
- void
- Tab()
- X{
- X#ifdef LISP
- X if (MajorMode(LISPMODE) && (bolp() || !eolp())) {
- X int dotchar = curchar;
- X Mark *m = 0;
- X
- X ToIndent();
- X if (dotchar > curchar)
- X m = MakeMark(curline, dotchar, M_FLOATER);
- X (void) lisp_indent();
- X if (m) {
- X ToMark(m);
- X DelMark(m);
- X } else
- X ToIndent();
- X return;
- X }
- X#endif
- X if (MajorMode(CMODE) && strlen(linebuf) == 0)
- X (void) c_indent(CIndIncrmt);
- X else
- X SelfInsert();
- X}
- X
- void
- QuotChar()
- X{
- X int c,
- X slow;
- X
- X c = waitchar(&slow);
- X if (slow)
- X message(key_strokes);
- X if (c != CTL('@'))
- X Insert(c);
- X}
- X
- X/* Insert the paren. If in C mode and c is a '}' then insert the
- X '}' in the "right" place for C indentation; that is indented
- X the same amount as the matching '{' is indented. */
- X
- int PDelay = 5, /* 1/2 a second */
- X CIndIncrmt = 8;
- X
- void
- DoParen()
- X{
- X Bufpos *bp = (Bufpos *) -1;
- X int nx,
- X c = LastKeyStruck;
- X
- X if (!isclosep(c)) {
- X SelfInsert();
- X return;
- X }
- X
- X if (MajorMode(CMODE) && c == '}' && blnkp(linebuf))
- X bp = c_indent(0);
- X#ifdef LISP
- X if (MajorMode(LISPMODE) && c == ')' && blnkp(linebuf))
- X bp = lisp_indent();
- X#endif
- X SelfInsert();
- X#ifdef MAC
- X if (MinorMode(ShowMatch) && !in_macro()) {
- X#else
- X if (MinorMode(ShowMatch) && !charp() && !in_macro()) {
- X#endif
- X b_char(1); /* Back onto the ')' */
- X if ((int) bp == -1)
- X bp = m_paren(c, BACKWARD, NO, YES);
- X f_char(1);
- X if (bp != 0) {
- X nx = in_window(curwind, bp->p_line);
- X if (nx != -1) { /* is visible */
- X Bufpos b;
- X
- X DOTsave(&b);
- X SetDot(bp);
- X SitFor(PDelay);
- X SetDot(&b);
- X } else
- X s_mess("%s", lcontents(bp->p_line));
- X }
- X mp_error(); /* display error message */
- X }
- X}
- X
- void
- LineAI()
- X{
- X DoNewline(TRUE);
- X}
- X
- void
- Newline()
- X{
- X DoNewline(MinorMode(Indent));
- X}
- X
- void
- DoNewline(indentp)
- X{
- X Bufpos save;
- X int indent;
- X
- X /* first we calculate the indent of the current line */
- X DOTsave(&save);
- X ToIndent();
- X indent = calc_pos(linebuf, curchar);
- X SetDot(&save);
- X
- X#ifdef ABBREV
- X MaybeAbbrevExpand();
- X#endif
- X#ifdef LISP
- X if (MajorMode(LISPMODE))
- X DelWtSpace();
- X else
- X#endif
- X if (indentp || blnkp(linebuf))
- X DelWtSpace();
- X
- X /* If there is more than 2 blank lines in a row then don't make
- X a newline, just move down one. */
- X if (arg_value() == 1 && eolp() && TwoBlank())
- X SetLine(curline->l_next);
- X else
- X LineInsert(arg_value());
- X
- X if (indentp)
- X#ifdef LISP
- X if (MajorMode(LISPMODE))
- X (void) lisp_indent();
- X else
- X#endif
- X n_indent((LMargin == 0) ? indent : LMargin);
- X}
- X
- void
- ins_str(str, ok_nl)
- register char *str;
- X{
- X register char c;
- X Bufpos save;
- X int llen;
- X
- X if (*str == 0)
- X return; /* ain't nothing to insert! */
- X DOTsave(&save);
- X llen = strlen(linebuf);
- X while (c = *str++) {
- X if (c == '\n' || (ok_nl && llen >= LBSIZE - 2)) {
- X IFixMarks(save.p_line, save.p_char, curline, curchar);
- X modify();
- X makedirty(curline);
- X LineInsert(1);
- X DOTsave(&save);
- X llen = strlen(linebuf);
- X }
- X if (c != '\n') {
- X ins_c(c, linebuf, curchar++, 1, LBSIZE);
- X llen += 1;
- X }
- X }
- X IFixMarks(save.p_line, save.p_char, curline, curchar);
- X modify();
- X makedirty(curline);
- X}
- X
- void
- open_lines(n)
- X{
- X Bufpos dot;
- X
- X DOTsave(&dot);
- X LineInsert(n); /* Open the lines... */
- X SetDot(&dot);
- X}
- X
- void
- OpenLine()
- X{
- X open_lines(arg_value());
- X}
- X
- X/* Take the region FLINE/FCHAR to TLINE/TCHAR and insert it at
- X ATLINE/ATCHAR in WHATBUF. */
- X
- Bufpos *
- DoYank(fline, fchar, tline, tchar, atline, atchar, whatbuf)
- Line *fline,
- X *tline,
- X *atline;
- Buffer *whatbuf;
- X{
- X register Line *newline;
- X static Bufpos bp;
- X char save[LBSIZE],
- X buf[LBSIZE];
- X Line *startline = atline;
- X int startchar = atchar;
- X
- X lsave();
- X if (whatbuf)
- X modify();
- X (void) ltobuf(atline, genbuf);
- X strcpy(save, &genbuf[atchar]);
- X
- X (void) ltobuf(fline, buf);
- X if (fline == tline)
- X buf[tchar] = '\0';
- X
- X linecopy(genbuf, atchar, &buf[fchar]);
- X atline->l_dline = putline(genbuf);
- X makedirty(atline);
- X
- X fline = fline->l_next;
- X while (fline != tline->l_next) {
- X newline = listput(whatbuf, atline);
- X newline->l_dline = fline->l_dline;
- X makedirty(newline);
- X fline = fline->l_next;
- X atline = newline;
- X atchar = 0;
- X }
- X
- X getline(atline->l_dline, genbuf);
- X atchar += tchar;
- X linecopy(genbuf, atchar, save);
- X atline->l_dline = putline(genbuf);
- X makedirty(atline);
- X IFixMarks(startline, startchar, atline, atchar);
- X bp.p_line = atline;
- X bp.p_char = atchar;
- X this_cmd = YANKCMD;
- X getDOT(); /* Whatever used to be in linebuf */
- X return &bp;
- X}
- X
- void
- YankPop()
- X{
- X Line *line,
- X *last;
- X Mark *mp = CurMark();
- X Bufpos *dot;
- X int dir = -1; /* Direction to rotate the ring */
- X
- X if (last_cmd != YANKCMD)
- X complain("Yank something first!");
- X
- X lfreelist(reg_delete(mp->m_line, mp->m_char, curline, curchar));
- X
- X /* Now must find a recently killed region. */
- X
- X if (arg_value() < 0)
- X dir = 1;
- X
- X killptr += dir;
- X for (;;) {
- X if (killptr < 0)
- X killptr = NUMKILLS - 1;
- X else if (killptr >= NUMKILLS)
- X killptr = 0;
- X if (killbuf[killptr])
- X break;
- X killptr += dir;
- X }
- X
- X this_cmd = YANKCMD;
- X
- X line = killbuf[killptr];
- X last = lastline(line);
- X dot = DoYank(line, 0, last, length(last), curline, curchar, curbuf);
- X MarkSet(CurMark(), curline, curchar);
- X SetDot(dot);
- X}
- X
- X/* This is an attempt to reduce the amount of memory taken up by each line.
- X Without this each malloc of a line uses sizeof (line) + sizeof(HEADER)
- X where line is 3 words and HEADER is 1 word.
- X This is going to allocate memory in chucks of CHUNKSIZE * sizeof (line)
- X and divide each chuck into lineS. A line is free in a chunk when its
- X line->l_dline == 0, so freeline sets dline to 0. */
- X
- X#define CHUNKSIZE 300
- X
- struct chunk {
- X int c_nlines; /* Number of lines in this chunk (so they
- X don't all have to be CHUNKSIZE long). */
- X Line *c_block; /* Chunk of memory */
- X struct chunk *c_nextfree; /* Next chunk of lines */
- X};
- X
- private struct chunk *fchunk = 0;
- private Line *ffline = 0; /* First free line */
- X
- void
- freeline(line)
- register Line *line;
- X{
- X line->l_dline = 0;
- X line->l_next = ffline;
- X if (ffline)
- X ffline->l_prev = line;
- X line->l_prev = 0;
- X ffline = line;
- X}
- X
- void
- lfreelist(first)
- register Line *first;
- X{
- X if (first)
- X lfreereg(first, lastline(first));
- X}
- X
- X/* Append region from line1 to line2 onto the free list of lines */
- X
- void
- lfreereg(line1, line2)
- register Line *line1,
- X *line2;
- X{
- X register Line *next,
- X *last = line2->l_next;
- X
- X while (line1 != last) {
- X next = line1->l_next;
- X freeline(line1);
- X line1 = next;
- X }
- X}
- X
- private int
- newchunk()
- X{
- X register Line *newline;
- X register int i;
- X struct chunk *f;
- X int nlines = CHUNKSIZE;
- X
- X f = (struct chunk *) emalloc(sizeof (struct chunk));
- X if (f == 0)
- X return 0;
- X
- X if ((f->c_block = (Line *) malloc((unsigned) (sizeof (Line) * nlines))) == 0) {
- X while (nlines > 0) {
- X f->c_block = (Line *) malloc((unsigned) (sizeof (Line) * nlines));
- X if (f->c_block != 0)
- X break;
- X nlines /= 2;
- X }
- X }
- X
- X if (nlines <= 0)
- X return 0;
- X
- X f->c_nlines = nlines;
- X for (i = 0, newline = f->c_block; i < nlines; newline++, i++)
- X freeline(newline);
- X f->c_nextfree = fchunk;
- X fchunk = f;
- X return 1;
- X}
- X
- X/* New BUFfer LINE */
- X
- Line *
- nbufline()
- X{
- X register Line *newline;
- X
- X if (ffline == 0) /* No free list */
- X if (newchunk() == 0)
- X complain("[Out of lines] ");
- X newline = ffline;
- X ffline = ffline->l_next;
- X if (ffline)
- X ffline->l_prev = 0;
- X return newline;
- X}
- X
- X/* Remove the free lines, in chunk c, from the free list because they are
- X no longer free. */
- X
- private void
- remfreelines(c)
- register struct chunk *c;
- X{
- X register Line *lp;
- X register int i;
- X
- X for (lp = c->c_block, i = 0; i < c->c_nlines; i++, lp++) {
- X if (lp->l_prev)
- X lp->l_prev->l_next = lp->l_next;
- X else
- X ffline = lp->l_next;
- X if (lp->l_next)
- X lp->l_next->l_prev = lp->l_prev;
- X }
- X}
- X
- X/* This is used to garbage collect the chunks of lines when malloc fails
- X and we are NOT looking for a new buffer line. This goes through each
- X chunk, and if every line in a given chunk is not allocated, the entire
- X chunk is `free'd by "free()". */
- X
- void
- GCchunks()
- X{
- X register struct chunk *cp;
- X struct chunk *prev = 0,
- X *next = 0;
- X register int i;
- X register Line *newline;
- X
- X for (cp = fchunk; cp != 0; cp = next) {
- X for (i = 0, newline = cp->c_block; i < cp->c_nlines; newline++, i++)
- X if (newline->l_dline != 0)
- X break;
- X
- X next = cp->c_nextfree;
- X
- X if (i == cp->c_nlines) { /* Unlink it!!! */
- X if (prev)
- X prev->c_nextfree = cp->c_nextfree;
- X else
- X fchunk = cp->c_nextfree;
- X remfreelines(cp);
- X free((char *) cp->c_block);
- X free((char *) cp);
- X } else
- X prev = cp;
- X }
- X}
- X
- X#ifdef LISP
- X
- X/* Grind S-Expr */
- X
- void
- GSexpr()
- X{
- X Bufpos dot,
- X end;
- X
- X if (linebuf[curchar] != '(')
- X complain((char *) 0);
- X DOTsave(&dot);
- X FSexpr();
- X DOTsave(&end);
- X SetDot(&dot);
- X for (;;) {
- X if (curline == end.p_line)
- X break;
- X line_move(FORWARD, 1, NO);
- X if (!blnkp(linebuf))
- X (void) lisp_indent();
- X }
- X SetDot(&dot);
- X}
- X
- X/* lisp_indent() indents a new line in Lisp Mode, according to where
- X the matching close-paren would go if we typed that (sort of). */
- X
- private Table *specials = NIL;
- X
- private void
- init_specials()
- X{
- X static char *words[] = {
- X "case",
- X "def",
- X "dolist",
- X "fluid-let",
- X "lambda",
- X "let",
- X "lexpr",
- X "macro",
- X "named-l", /* named-let and named-lambda */
- X "nlambda",
- X "prog",
- X "selectq",
- X 0
- X };
- X char **wordp = words;
- X
- X specials = make_table();
- X while (*wordp)
- X add_word(*wordp++, specials);
- X}
- X
- void
- AddSpecial()
- X{
- X char *word;
- X
- X word = ask((char *) 0, ProcFmt);
- X if (specials == NIL)
- X init_specials();
- X add_word(copystr(word), specials);
- X}
- X
- Bufpos *
- lisp_indent()
- X{
- X Bufpos *bp,
- X savedot;
- X int goal;
- X
- X bp = m_paren(')', BACKWARD, NO, YES);
- X
- X if (bp == 0)
- X return 0;
- X
- X /* We want to end up
- X
- X (atom atom atom ...
- X ^ here.
- X */
- X
- X DOTsave(&savedot);
- X SetDot(bp);
- X f_char(1);
- X if (linebuf[curchar] != '(') {
- X register Word *wp;
- X
- X if (specials == NIL)
- X init_specials();
- X for (wp = table_top(specials); wp != NIL; wp = next_word(wp))
- X if (casencmp(word_text(wp), &linebuf[curchar], word_length(wp)) == 0)
- X break;
- X if (wp == NIL) { /* not special */
- X int c_char = curchar;
- X
- X WITH_TABLE(curbuf->b_major)
- X f_word(1);
- X END_TABLE();
- X if (LookingAt("[ \t]*;\\|[ \t]*$", linebuf, curchar))
- X curchar = c_char;
- X else while (linebuf[curchar] == ' ')
- X curchar += 1;
- X } else
- X curchar += 1;
- X }
- X goal = calc_pos(linebuf, curchar);
- X SetDot(&savedot);
- X n_indent(goal);
- X
- X return bp;
- X}
- X#endif /* LISP */
- END_OF_FILE
- if test 14465 -ne `wc -c <'./insert.c'`; then
- echo shar: \"'./insert.c'\" unpacked with wrong size!
- fi
- # end of './insert.c'
- fi
- if test -f './recover.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'./recover.c'\"
- else
- echo shar: Extracting \"'./recover.c'\" \(14306 characters\)
- sed "s/^X//" >'./recover.c' <<'END_OF_FILE'
- X/***************************************************************************
- X * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne. JOVE *
- X * is provided to you without charge, and with no warranty. You may give *
- X * away copies of JOVE, including sources, provided that this notice is *
- X * included in all the files. *
- X ***************************************************************************/
- X
- X/* Recovers JOVE files after a system/editor crash.
- X Usage: recover [-d directory] [-syscrash]
- X The -syscrash option is specified in /etc/rc and what it does is
- X move all the jove tmp files from TMP_DIR to REC_DIR.
- X
- X The -d option lets you specify the directory to search for tmp files when
- X the default isn't the right one.
- X
- X Look in Makefile to change the default directories. */
- X
- X#include <stdio.h> /* Do stdio first so it doesn't override OUR
- X definitions. */
- X#undef EOF
- X#undef BUFSIZ
- X#undef putchar
- X#undef getchar
- X
- X#define STDIO
- X
- X#include "jove.h"
- X#include "temp.h"
- X#include "rec.h"
- X#include <signal.h>
- X#include <sys/file.h>
- X#include <sys/stat.h>
- X#include <sys/dir.h>
- X
- X#ifndef L_SET
- X# define L_SET 0
- X# define L_INCR 1
- X#endif
- X
- char blk_buf[BUFSIZ];
- int nleft;
- FILE *ptrs_fp;
- int data_fd;
- struct rec_head Header;
- char datafile[40],
- X pntrfile[40];
- long Nchars,
- X Nlines;
- char tty[] = "/dev/tty";
- int UserID,
- X Verbose = 0;
- char *Directory = 0; /* the directory we're looking in */
- X
- struct file_pair {
- X char *file_data,
- X *file_rec;
- X#define INSPECTED 01
- X int file_flags;
- X struct file_pair *file_next;
- X} *First = 0,
- X *Last = 0;
- X
- struct rec_entry *buflist[100] = {0};
- X
- X#ifndef BSD4_2
- X
- typedef struct {
- X int d_fd; /* File descriptor for this directory */
- X} DIR;
- X
- DIR *
- opendir(dir)
- char *dir;
- X{
- X DIR *dp = (DIR *) malloc(sizeof *dp);
- X
- X if ((dp->d_fd = open(dir, 0)) == -1)
- X return NULL;
- X return dp;
- X}
- X
- closedir(dp)
- DIR *dp;
- X{
- X (void) close(dp->d_fd);
- X free(dp);
- X}
- X
- struct direct *
- readdir(dp)
- DIR *dp;
- X{
- X static struct direct dir;
- X
- X do
- X if (read(dp->d_fd, &dir, sizeof dir) != sizeof dir)
- X return NULL;
- X#if defined(elxsi) && defined(SYSV)
- X /*
- X * Elxsi has a BSD4.2 implementation which may or may not use
- X * `twisted inodes' ... Anyone able to check?
- X */
- X while (*(unsigned short *)&dir.d_ino == 0);
- X#else
- X while (dir.d_ino == 0);
- X#endif
- X
- X return &dir;
- X}
- X
- X#endif /* BSD4_2 */
- X
- X/* Get a line at `tl' in the tmp file into `buf' which should be LBSIZE
- X long. */
- X
- getline(tl, buf)
- disk_line tl;
- char *buf;
- X{
- X register char *bp,
- X *lp;
- X register int nl;
- X char *getblock();
- X
- X lp = buf;
- X bp = getblock(tl >> 1);
- X nl = nleft;
- X tl = blk_round(tl);
- X
- X while (*lp++ = *bp++) {
- X if (--nl == 0) {
- X tl = forward_block(tl);
- X bp = getblock(tl >> 1);
- X nl = nleft;
- X }
- X }
- X}
- X
- char *
- getblock(atl)
- disk_line atl;
- X{
- X int bno,
- X off;
- X static int curblock = -1;
- X
- X bno = da_to_bno(atl);
- X off = da_to_off(atl);
- X nleft = BUFSIZ - off;
- X
- X if (bno != curblock) {
- X lseek(data_fd, (long) bno * BUFSIZ, L_SET);
- X read(data_fd, blk_buf, BUFSIZ);
- X curblock = bno;
- X }
- X return blk_buf + off;
- X}
- X
- char *
- copystr(s)
- char *s;
- X{
- X char *str;
- X
- X str = malloc(strlen(s) + 1);
- X strcpy(str, s);
- X
- X return str;
- X}
- X
- X/* Scandir returns the number of entries or -1 if the directory cannoot
- X be opened or malloc fails. */
- X
- scandir(dir, nmptr, qualify, sorter)
- char *dir;
- struct direct ***nmptr;
- int (*qualify)();
- struct direct *(*sorter)();
- X{
- X DIR *dirp;
- X struct direct *entry,
- X **ourarray;
- X int nalloc = 10,
- X nentries = 0;
- X
- X if ((dirp = opendir(dir)) == NULL)
- X return -1;
- X ourarray = (struct direct **) malloc(nalloc * sizeof (struct direct *));
- X while ((entry = readdir(dirp)) != NULL) {
- X if (qualify != 0 && (*qualify)(entry) == 0)
- X continue;
- X if (nentries == nalloc) {
- X ourarray = (struct direct **) realloc(ourarray, (nalloc += 10) * sizeof (struct direct));
- X if (ourarray == NULL)
- X return -1;
- X }
- X ourarray[nentries] = (struct direct *) malloc(sizeof *entry);
- X *ourarray[nentries] = *entry;
- X nentries += 1;
- X }
- X closedir(dirp);
- X if (nentries != nalloc)
- X ourarray = (struct direct **) realloc(ourarray,
- X (nentries * sizeof (struct direct)));
- X if (sorter != 0)
- X qsort(ourarray, nentries, sizeof (struct direct **), sorter);
- X *nmptr = ourarray;
- X
- X return nentries;
- X}
- X
- alphacomp(a, b)
- struct direct **a,
- X **b;
- X{
- X return strcmp((*a)->d_name, (*b)->d_name);
- X}
- X
- char *CurDir;
- X
- X/* Scan the DIRNAME directory for jove tmp files, and make a linked list
- X out of them. */
- X
- get_files(dirname)
- char *dirname;
- X{
- X int add_name();
- X struct direct **nmptr;
- X
- X CurDir = dirname;
- X scandir(dirname, &nmptr, add_name, (int (*)())0);
- X}
- X
- add_name(dp)
- struct direct *dp;
- X{
- X char dfile[128],
- X rfile[128];
- X struct file_pair *fp;
- X struct rec_head header;
- X int fd;
- X
- X if (strncmp(dp->d_name, "jrec", 4) != 0)
- X return 0;
- X /* If we get here, we found a "recover" tmp file, so now
- X we look for the corresponding "data" tmp file. First,
- X though, we check to see whether there is anything in
- X the "recover" file. If it's 0 length, there's no point
- X in saving its name. */
- X (void) sprintf(rfile, "%s/%s", CurDir, dp->d_name);
- X (void) sprintf(dfile, "%s/jove%s", CurDir, dp->d_name + 4);
- X if ((fd = open(rfile, 0)) != -1) {
- X if ((read(fd, (char *) &header, sizeof header) != sizeof header)) {
- X close(fd);
- X return 0;
- X } else
- X close(fd);
- X }
- X if (access(dfile, 0) != 0) {
- X fprintf(stderr, "recover: can't find the data file for %s/%s\n", Directory, dp->d_name);
- X fprintf(stderr, "so deleting...\n");
- X (void) unlink(rfile);
- X (void) unlink(dfile);
- X return 0;
- X }
- X /* If we get here, we've found both files, so we put them
- X in the list. */
- X fp = (struct file_pair *) malloc (sizeof *fp);
- X if ((char *) fp == 0) {
- X fprintf(stderr, "recover: cannot malloc for file_pair.\n");
- X exit(-1);
- X }
- X fp->file_data = copystr(dfile);
- X fp->file_rec = copystr(rfile);
- X fp->file_flags = 0;
- X fp->file_next = First;
- X First = fp;
- X
- X return 1;
- X}
- X
- options()
- X{
- X printf("Options are:\n");
- X printf(" ? list options.\n");
- X printf(" get get a buffer to a file.\n");
- X printf(" list list known buffers.\n");
- X printf(" print print a buffer to terminal.\n");
- X printf(" quit quit and delete jove tmp files.\n");
- X printf(" restore restore all buffers.\n");
- X}
- X
- X/* Returns a legitimate buffer # */
- X
- struct rec_entry **
- getsrc()
- X{
- X char name[128];
- X int number;
- X
- X for (;;) {
- X tellme("Which buffer ('?' for list)? ", name);
- X if (name[0] == '?')
- X list();
- X else if (name[0] == '\0')
- X return 0;
- X else if ((number = atoi(name)) > 0 && number <= Header.Nbuffers)
- X return &buflist[number];
- X else {
- X int i;
- X
- X for (i = 1; i <= Header.Nbuffers; i++)
- X if (strcmp(buflist[i]->r_bname, name) == 0)
- X return &buflist[i];
- X printf("%s: unknown buffer.\n", name);
- X }
- X }
- X}
- X
- X/* Get a destination file name. */
- X
- static char *
- getdest()
- X{
- X static char filebuf[256];
- X
- X tellme("Output file: ", filebuf);
- X if (filebuf[0] == '\0')
- X return 0;
- X return filebuf;
- X}
- X
- X#include "ctype.h"
- X
- char *
- readword(buf)
- char *buf;
- X{
- X int c;
- X char *bp = buf;
- X
- X while (index(" \t\n", c = getchar()))
- X ;
- X
- X do {
- X if (index(" \t\n", c))
- X break;
- X *bp++ = c;
- X } while ((c = getchar()) != EOF);
- X *bp = 0;
- X
- X return buf;
- X}
- X
- tellme(quest, answer)
- char *quest,
- X *answer;
- X{
- X if (stdin->_cnt <= 0) {
- X printf("%s", quest);
- X fflush(stdout);
- X }
- X readword(answer);
- X}
- X
- X/* Print the specified file to strandard output. */
- X
- jmp_buf int_env;
- X
- catch()
- X{
- X longjmp(int_env, 1);
- X}
- X
- restore()
- X{
- X register int i;
- X char tofile[100],
- X answer[30];
- X int nrecovered = 0;
- X
- X for (i = 1; i <= Header.Nbuffers; i++) {
- X (void) sprintf(tofile, "#%s", buflist[i]->r_bname);
- tryagain:
- X printf("Restoring %s to %s, okay?", buflist[i]->r_bname,
- X tofile);
- X tellme(" ", answer);
- X switch (answer[0]) {
- X case 'y':
- X break;
- X
- X case 'n':
- X continue;
- X
- X default:
- X tellme("What file should I use instead? ", tofile);
- X goto tryagain;
- X }
- X get(&buflist[i], tofile);
- X nrecovered += 1;
- X }
- X printf("Recovered %d buffers.\n", nrecovered);
- X}
- X
- get(src, dest)
- struct rec_entry **src;
- char *dest;
- X{
- X FILE *outfile;
- X
- X if (src == 0 || dest == 0)
- X return;
- X (void) signal(SIGINT, catch);
- X if (setjmp(int_env) == 0) {
- X if ((outfile = fopen(dest, "w")) == NULL) {
- X printf("recover: cannot create %s.\n", dest);
- X return;
- X }
- X if (dest != tty)
- X printf("\"%s\"", dest);
- X dump_file(src - buflist, outfile);
- X } else
- X printf("\nAborted!\n");
- X fclose(outfile);
- X if (dest != tty)
- X printf(" %ld lines, %ld characters.\n", Nlines, Nchars);
- X (void) signal(SIGINT, SIG_DFL);
- X}
- X
- char **
- scanvec(args, str)
- register char **args,
- X *str;
- X{
- X while (*args) {
- X if (strcmp(*args, str) == 0)
- X return args;
- X args += 1;
- X }
- X return 0;
- X}
- X
- read_rec(recptr)
- struct rec_entry *recptr;
- X{
- X if (fread((char *) recptr, sizeof *recptr, 1, ptrs_fp) != 1)
- X fprintf(stderr, "recover: cannot read record.\n");
- X}
- X
- seekto(which)
- X{
- X struct rec_entry rec;
- X long offset;
- X int i;
- X
- X offset = sizeof (Header) + (Header.Nbuffers * sizeof (rec));
- X for (i = 1; i < which; i++)
- X offset += buflist[i]->r_nlines * sizeof (disk_line);
- X fseek(ptrs_fp, offset, L_SET);
- X}
- X
- makblist()
- X{
- X int i;
- X
- X fseek(ptrs_fp, (long) sizeof (Header), L_SET);
- X for (i = 1; i <= Header.Nbuffers; i++) {
- X if (buflist[i] == 0)
- X buflist[i] = (struct rec_entry *) malloc (sizeof (struct rec_entry));
- X read_rec(buflist[i]);
- X }
- X while (buflist[i]) {
- X free((char *) buflist[i]);
- X buflist[i] = 0;
- X i += 1;
- X }
- X}
- X
- disk_line
- getaddr(fp)
- register FILE *fp;
- X{
- X register int nchars = sizeof (disk_line);
- X disk_line addr;
- X register char *cp = (char *) &addr;
- X
- X while (--nchars >= 0)
- X *cp++ = getc(fp);
- X
- X return addr;
- X}
- X
- dump_file(which, out)
- FILE *out;
- X{
- X register int nlines;
- X register disk_line daddr;
- X char buf[BUFSIZ];
- X
- X seekto(which);
- X nlines = buflist[which]->r_nlines;
- X Nchars = Nlines = 0L;
- X while (--nlines >= 0) {
- X daddr = getaddr(ptrs_fp);
- X getline(daddr, buf);
- X Nlines += 1;
- X Nchars += 1 + strlen(buf);
- X fputs(buf, out);
- X if (nlines > 0)
- X fputc('\n', out);
- X }
- X if (out != stdout)
- X fclose(out);
- X}
- X
- X/* List all the buffers. */
- X
- list()
- X{
- X int i;
- X
- X for (i = 1; i <= Header.Nbuffers; i++)
- X printf("%d) buffer %s \"%s\" (%d lines)\n", i,
- X buflist[i]->r_bname,
- X buflist[i]->r_fname,
- X buflist[i]->r_nlines);
- X}
- X
- doit(fp)
- struct file_pair *fp;
- X{
- X char answer[30];
- X char *datafile = fp->file_data,
- X *pntrfile = fp->file_rec;
- X
- X ptrs_fp = fopen(pntrfile, "r");
- X if (ptrs_fp == NULL) {
- X if (Verbose)
- X fprintf(stderr, "recover: cannot read rec file (%s).\n", pntrfile);
- X return 0;
- X }
- X fread((char *) &Header, sizeof Header, 1, ptrs_fp);
- X if (Header.Uid != UserID)
- X return 0;
- X
- X /* Don't ask about JOVE's that are still running ... */
- X#ifdef KILL0
- X if (kill(Header.Pid, 0) == 0)
- X return 0;
- X#endif /* KILL0 */
- X
- X if (Header.Nbuffers == 0) {
- X printf("There are no modified buffers in %s; should I delete the tmp file?", pntrfile);
- X ask_del(" ", fp);
- X return 1;
- X }
- X
- X if (Header.Nbuffers < 0) {
- X fprintf(stderr, "recover: %s doesn't look like a jove file.\n", pntrfile);
- X ask_del("Should I delete it? ", fp);
- X return 1; /* We'll, we sort of found something. */
- X }
- X printf("Found %d buffer%s last updated: %s",
- X Header.Nbuffers,
- X Header.Nbuffers != 1 ? "s" : "",
- X ctime(&Header.UpdTime));
- X data_fd = open(datafile, 0);
- X if (data_fd == -1) {
- X fprintf(stderr, "recover: but I can't read the data file (%s).\n", datafile);
- X ask_del("Should I delete the tmp files? ", fp);
- X return 1;
- X }
- X makblist();
- X list();
- X
- X for (;;) {
- X tellme("(Type '?' for options): ", answer);
- X switch (answer[0]) {
- X case '\0':
- X continue;
- X
- X case '?':
- X options();
- X break;
- X
- X case 'l':
- X list();
- X break;
- X
- X case 'p':
- X get(getsrc(), tty);
- X break;
- X
- X case 'q':
- X ask_del("Shall I delete the tmp files? ", fp);
- X return 1;
- X
- X case 'g':
- X { /* So it asks for src first. */
- X char *dest;
- X struct rec_entry **src;
- X
- X if ((src = getsrc()) == 0)
- X break;
- X dest = getdest();
- X get(src, dest);
- X break;
- X }
- X
- X case 'r':
- X restore();
- X break;
- X
- X default:
- X printf("I don't know how to \"%s\"!\n", answer);
- X break;
- X }
- X }
- X}
- X
- ask_del(prompt, fp)
- char *prompt;
- struct file_pair *fp;
- X{
- X char yorn[20];
- X
- X tellme(prompt, yorn);
- X if (yorn[0] == 'y')
- X del_files(fp);
- X}
- X
- del_files(fp)
- struct file_pair *fp;
- X{
- X (void) unlink(fp->file_data);
- X (void) unlink(fp->file_rec);
- X}
- X
- X#ifdef notdef
- savetmps()
- X{
- X struct file_pair *fp;
- X int status,
- X pid;
- X
- X if (strcmp(TMP_DIR, REC_DIR) == 0)
- X return; /* Files are moved to the same place. */
- X get_files(TMP_DIR);
- X for (fp = First; fp != 0; fp = fp->file_next) {
- X switch (pid = fork()) {
- X case -1:
- X fprintf(stderr, "recover: can't fork\n!");
- X exit(-1);
- X
- X case 0:
- X execl("/bin/cp", "cp", fp->file_data, fp->file_rec,
- X REC_DIR, (char *)0);
- X fprintf(stderr, "recover: cannot execl /bin/cp.\n");
- X exit(-1);
- X
- X default:
- X while (wait(&status) != pid)
- X ;
- X if (status != 0)
- X fprintf(stderr, "recover: non-zero status (%d) returned from copy.\n", status);
- X }
- X }
- X}
- X#endif
- X
- lookup(dir)
- char *dir;
- X{
- X struct file_pair *fp;
- X struct rec_head header;
- X char yorn[20];
- X int nfound = 0,
- X this_one;
- X
- X printf("Checking %s ...\n", dir);
- X Directory = dir;
- X get_files(dir);
- X for (fp = First; fp != 0; fp = fp->file_next) {
- X nfound += doit(fp);
- X if (ptrs_fp)
- X (void) fclose(ptrs_fp);
- X if (data_fd > 0)
- X (void) close(data_fd);
- X }
- X return nfound;
- X}
- X
- main(argc, argv)
- int argc;
- char *argv[];
- X{
- X int nfound;
- X char **argvp;
- X
- X UserID = getuid();
- X
- X if (scanvec(argv, "-help")) {
- X printf("recover: usage: recover [-d directory]\n");
- X printf("Use \"recover\" after JOVE has died for some\n");
- X printf("unknown reason.\n\n");
- X/* printf("Use \"recover -syscrash\" when the system is in the process\n");
- X printf("of rebooting. This is done automatically at reboot time\n");
- X printf("and so most of you don't have to worry about that.\n\n");
- X */
- X printf("Use \"recover -d directory\" when the tmp files are store\n");
- X printf("in DIRECTORY instead of the default one (/tmp).\n");
- X exit(0);
- X }
- X if (scanvec(argv, "-v"))
- X Verbose = YES;
- X/* if (scanvec(argv, "-syscrash")) {
- X printf("Recovering jove files ... ");
- X savetmps();
- X printf("Done.\n");
- X exit(0);
- X } */
- X if (argvp = scanvec(argv, "-uid"))
- X UserID = atoi(argvp[1]);
- X if (argvp = scanvec(argv, "-d"))
- X nfound = lookup(argvp[1]);
- X else
- X nfound = lookup(TmpFilePath);
- X if (nfound == 0)
- X printf("There's nothing to recover.\n");
- X}
- END_OF_FILE
- if test 14306 -ne `wc -c <'./recover.c'`; then
- echo shar: \"'./recover.c'\" unpacked with wrong size!
- fi
- # end of './recover.c'
- fi
- echo shar: End of archive 7 \(of 21\).
- cp /dev/null ark7isdone
- MISSING=""
- for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 21 archives.
- rm -f ark[1-9]isdone ark[1-9][0-9]isdone
- else
- echo You still need to unpack the following archives:
- echo " " ${MISSING}
- fi
- ## End of shell archive.
- exit 0
-